use std::str::FromStr;

use serde::{Serialize,Deserialize};
use utoipa::{ToSchema,IntoParams};
use chat_core::Message;

use crate::{AppState, ChatFile, error::AppError};


#[derive(Debug,Serialize,Deserialize,ToSchema,Clone)]
pub struct CreateMessage {
    pub content: String,
    #[serde(default)]
    pub files: Vec<String>,
}

#[derive(Debug,Serialize,Deserialize,ToSchema,Clone,IntoParams)]
pub struct ListMessages {
    #[serde(default)]
    pub last_id: Option<u64>,
    #[serde(default)]
    pub limit: u64,
}

impl AppState {
    pub async fn create_message(
        &self,
        input: CreateMessage,
        chat_id: u64,
        user_id: u64,
    ) -> Result<Message,AppError> {
        let base_id = &self.config.server.base_dir;
        if input.content.is_empty(){
            return Err(AppError::CreateMessageError("Message content cannot be empty".to_string()));
        }

        for s in &input.files {
            let file = ChatFile::from_str(s)?;
            if !file.path(base_id).exists() {
                return Err(AppError::CreateMessageError(format!(
                    "File not found: {}",s
                )));
            }
        }
        let message = sqlx::query_as(
            "
            INSERT INTO messages (chat_id,sender_id,content,files)
            VALUES ($1,$2,$3,$4)
            RETURNING id,chat_id,sender_id,content,files,created_at
            "
        )
        .bind(chat_id as i64)
        .bind(user_id as i64)
        .bind(input.content)
        .bind(&input.files)
        .fetch_one(&self.pool)
        .await?;
        Ok(message)
    }

    pub async fn list_messages(
        &self,
        input: ListMessages,
        chat_id: u64,
    ) -> Result<Vec<Message>,AppError> {

        let last_id = input.last_id.unwrap_or(i64::MAX as _);
        let limit = match input.limit {
            0 => i64::MAX,
            1..100 => input.limit as _,
            _ => 100,
        };

        let messages = sqlx::query_as(
            "
            SELECT id,chat_id,sender_id,content,files,created_at
            FROM messages
            WHERE chat_id = $1
            AND id < $2
            ORDER BY created_at DESC
            LIMIT $3
            "
        )
        .bind(chat_id as i64)
        .bind(last_id as i64)
        .bind(limit)
        .fetch_all(&self.pool)
        .await?;
        Ok(messages)
    }
}